Preprocessing

Load necessary libraries for analysis

library(reshape2)
library(Seurat)
library(SeuratDisk)
library(ggplot2)
source("utils/utilFxns.R")
source("utils/plottingFxns.R")

Gene expression matrices (GEM) for each sequencing sample are converted from h5ad files to h5Seurat files and then read in. For this example, we will be reading in 8 different tree shrew samples.

# Set 
data_dir <- "/Users/joshhahn/Google Drive/My Drive/shekharlab_data/projects/Tree_shrew/TS_velo/"
 

Convert(paste0(data_dir, "treeshrew1_chx10_pos/velo_outs/full.h5ad"), dest = "h5seurat")
Chx10_pos1 <- LoadH5Seurat(paste0(data_dir, "treeshrew1_chx10_pos/velo_outs/full.h5seurat"))

Convert(paste0(data_dir, "treeshrew1_neun_chx10_neg/velo_outs/full.h5ad"), dest = "h5seurat")
N_C_neg1 <- LoadH5Seurat(paste0(data_dir, "treeshrew1_neun_chx10_neg/velo_outs/full.h5seurat"))

Convert(paste0(data_dir, "treeshrew1_neun_pos/velo_outs/full.h5ad"), dest = "h5seurat")
Neun_pos1 <- LoadH5Seurat(paste0(data_dir, "treeshrew1_neun_pos/velo_outs/full.h5seurat"))

Convert(paste0(data_dir, "treeshrew2_chx10_pos/velo_outs/full.h5ad"), dest = "h5seurat")
Chx10_pos2 <- LoadH5Seurat(paste0(data_dir, "treeshrew2_chx10_pos/velo_outs/full.h5seurat"))

Convert(paste0(data_dir, "treeshrew2_neun_chx10_neg/velo_outs/full.h5ad"), dest = "h5seurat")
N_C_neg2 <- LoadH5Seurat(paste0(data_dir, "treeshrew2_neun_chx10_neg/velo_outs/full.h5seurat"))

Convert(paste0(data_dir, "treeshrew2_neun_pos/velo_outs/full.h5ad"), dest = "h5seurat")
Neun_pos2 <- LoadH5Seurat(paste0(data_dir, "treeshrew2_neun_pos/velo_outs/full.h5seurat"))

Convert(paste0(data_dir, "TsChx10/velo_outs/full.h5ad"), dest = "h5seurat")
TsChx <- LoadH5Seurat(paste0(data_dir, "TsChx10/velo_outs/full.h5seurat"))

Convert(paste0(data_dir, "TsNueun/velo_outs/full.h5ad"), dest = "h5seurat")
TsNu <- LoadH5Seurat(paste0(data_dir, "TsNueun/velo_outs/full.h5seurat"))

GEMs from all sequencing runs are combined into a single Seurat object.

Shrew_mat <- cbind(Chx10_pos1@assays$matrix@counts, N_C_neg1@assays$matrix@counts, Neun_pos1@assays$matrix@counts, Chx10_pos2@assays$matrix@counts, N_C_neg2@assays$matrix@counts, Neun_pos2@assays$matrix@counts, TsChx@assays$matrix@counts, TsNu@assays$matrix@counts)

Shrew <- CreateSeuratObject(Shrew_mat, names.delim = ":")

Shrew@meta.data[colnames(Chx10_pos1), 'orig.file'] = "treeshrew1_chx10_pos"
Shrew@meta.data[colnames(Neun_pos1), 'orig.file'] = "treeshrew1_neun_pos"
Shrew@meta.data[colnames(N_C_neg1), 'orig.file'] = "treeshrew1_neun_chx10_neg"
Shrew@meta.data[colnames(Chx10_pos2), 'orig.file'] = "treeshrew2_chx10_pos"
Shrew@meta.data[colnames(Neun_pos2), 'orig.file'] = "treeshrew2_neun_pos"
Shrew@meta.data[colnames(N_C_neg2), 'orig.file'] = "treeshrew2_neun_chx10_neg"
Shrew@meta.data[colnames(TsChx), 'orig.file'] = "TsChx10"
Shrew@meta.data[colnames(TsNu), 'orig.file'] = "TsNueun"

The initial Tree Shrew object is provided.

Shrew <- readRDS("Objects/Shrew_all_cells_initial.rds")

Check each sequencing samples for any abnormalities.

VlnPlot(Shrew, features = "nCount_RNA", pt.size = 0, group.by = "orig.file", y.max = 50000)

VlnPlot(Shrew, features = "nFeature_RNA", pt.size = 0, group.by = "orig.file")

Cell class annotation

Cluster the data

Here we use a standard clustering pipeline to produce an initial set of clusters, which we will annotate into the major cell classes. The clustering pipeline has been condensed into a single function available in the utils folder.

Shrew <- ClusterSeurat(Shrew, cluster_resolution = 0.5, numPCs = 20)

Visualize initial clusters

DimPlot(Shrew, label = TRUE)

DimPlot(Shrew, group.by = "orig.file")

VlnPlot(Shrew, "nCount_RNA", pt.size = 0, y.max = 50000) + RotatedAxis()
Warning: Removed 5 rows containing non-finite values (stat_ydensity).

VlnPlot(Shrew, "nFeature_RNA", pt.size = 0, y.max = 6000) + RotatedAxis()
Warning: Removed 566 rows containing non-finite values (stat_ydensity).

Identify cell classes

Given the large number of clusters, recluster with a smaller resolution parameter.

Shrew <- FindClusters(Shrew, resolution = 0.2)
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 81902
Number of edges: 3285748

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.9910
Number of communities: 67
Elapsed time: 15 seconds
DimPlot(Shrew, label = TRUE)

DimPlot(Shrew, group.by = "orig.file")

VlnPlot(Shrew, "nCount_RNA", pt.size = 0, y.max = 50000) + RotatedAxis()
Warning: Removed 5 rows containing non-finite values (stat_ydensity).

VlnPlot(Shrew, "nFeature_RNA", pt.size = 0, y.max = 6000) + RotatedAxis()
Warning: Removed 566 rows containing non-finite values (stat_ydensity).

To assist in identifying cell classes, construct a dendrogram of the clusters. DendroOrder also creates a new metadata column ordered by the dendrogram.

Shrew <- DendroOrder(Shrew)

Construct a DotPlot of canonical markers, with clusters ordered by the dendrogram.

Annotate clusters using canonical marker genes.

Idents(Shrew) <- "seurat_clusters"

Shrew@meta.data$cell_class = "Unannotated"
Shrew@meta.data[WhichCells(Shrew, idents =c(54,43,24,36,35,6,15,2,3,4,32,25,57,18,44)),]$cell_class = "RGC"
Shrew@meta.data[WhichCells(Shrew, idents = c(22,46,52,20,27,37,53,50,58)),]$cell_class = "BP"
Shrew@meta.data[WhichCells(Shrew, idents = c(28)),]$cell_class = "HC"
Shrew@meta.data[WhichCells(Shrew, idents = c(7,42)),]$cell_class = "MG"
Shrew@meta.data[WhichCells(Shrew, idents = c(23, 34,21,40,45,9,19,16,62, 49,33,51,14,56,59,13,47,63,5,31,30,1,8,11,60,10,12,55,61)),]$cell_class = "AC"
Shrew@meta.data[WhichCells(Shrew, idents = c(0,65, 66,26,64)),]$cell_class = "PR"

# Retain clusters that don't express any canonical marker as "Other"
Shrew@meta.data[WhichCells(Shrew, idents = c(17,29,48,41,38,39)),]$cell_class = "Other"

Visualize the final annotations.

DimPlot(Shrew, group.by = "cell_class")

DotPlot(Shrew, features = c(RGC_markers, BC_markers, AC_markers, HC_markers, PR_markers, MG_markers, Other_markers), group.by = "cell_class") + RotatedAxis()

Save the object.

saveRDS(Shrew, "Objects/Shrew_all_cells_final.rds")

RGC clustering analysis

Now that we annotated the major cell classes, we will separate RGCs and BCs into separate objects and do another round of analysis.

We will only keep cells from samples enriched for NeuN. In addition, remove cells with abnormally high RNA counts.

# Only keep NeuN enriched samples
Shrew_RGC <- subset(Shrew_RGC, (orig.file == "treeshrew1_neun_pos") |  (orig.file == "treeshrew2_neun_pos") |  (orig.file == "TsNueun"))

# Remove cells with high RNA counts
Shrew_RGC <- subset(Shrew_RGC, subset = nCount_RNA < 25000)

Run clustering pipeline

Run the clustering pipeline again, performing data integration based on the original sample to correct for batch effects. Start with a cluster resolution of 0.8, which will be refined later.

Shrew_RGC <- ClusterSeurat(Shrew_RGC,  numPCs = 20, integrate.by = "orig.file", cluster_resolution = 0.8)

Visualize initial clusters.

DimPlot(Shrew_RGC, label = TRUE)

DimPlot(Shrew_RGC, group.by = "orig.file", shuffle = TRUE)

VlnPlot(Shrew_RGC, "nCount_RNA", pt.size = 0) + RotatedAxis()

VlnPlot(Shrew_RGC, "nFeature_RNA", pt.size = 0) + RotatedAxis()

Refine resolution parameter

Test a variety of resolution parameters.

DimPlot(Shrew_RGC, label = TRUE, group.by = "integrated_snn_res.0.5")
DimPlot(Shrew_RGC, label = TRUE, group.by = "integrated_snn_res.0.8")

DimPlot(Shrew_RGC, label = TRUE, group.by = "integrated_snn_res.1.1")

DimPlot(Shrew_RGC, label = TRUE, group.by = "integrated_snn_res.1.4")

Start with the clusters decided with a resolution of 1.4 and refine from there.

Shrew_RGC@meta.data$seurat_clusters <- Shrew_RGC@meta.data$integrated_snn_res.1.4
Idents(Shrew_RGC) <- "seurat_clusters"

Remove contaminant clusters

Check if any clusters have abnormally low counts or features.

VlnPlot(Shrew_RGC, "nCount_RNA", pt.size = 0) + RotatedAxis()

VlnPlot(Shrew_RGC, "nFeature_RNA", pt.size = 0) + RotatedAxis()

Examine canonical markers for any potential contaminant clusters.

DotPlot(Shrew_RGC, features = RGC_markers, assay = "RNA") + RotatedAxis()


DotPlot(Shrew_RGC, features = c(RGC_markers, BC_markers, AC_markers, HC_markers, Cone_markers, Rod_markers, MG_markers, Other_markers), assay = "RNA") + RotatedAxis()
Warning in FetchData(object = object, vars = features, cells = cells) :
  The following requested variables were not found: PDC, RHO

DotPlot(Shrew_RGC, features = AC_markers, assay = "RNA") + RotatedAxis()

Remove low quality / contaminant clusters.

# Drop cluster 0 and 32 due to low counts
Shrew_RGC <- DropClusters(Shrew_RGC, idents = c(0 ,32), refactor = FALSE)

# Remove clusters that express AC markers, as they are likely AC doublets.
# Cluster 32 expresses AC markers, but was already removed due to low counts.
Shrew_RGC <- DropClusters(Shrew_RGC, idents = c(13, 39:42, 44, 45, 48, 49 ), refactor = FALSE)

Merge clusters

Now that contaminants have been removed, reconstruct the neighborhood graph and UMAP.

Calculate top DE genes and plot using a dendrogram.

From the UMAP and DE Dot Plot, determine whether to merge certain clusters.

As most of the top markers for 36 are still expressed in 20, although at a lower expression level, merge the two clusters.

# 20, 36 - merge
Shrew_RGC <- MergeClusters(Shrew_RGC, idents = c(20,36), refactor = TRUE)

Summary Plots

BC clustering analysis

We will follow a similar process to now analyze bipolar cells.

Remove NeuN samples, as they enrich for different cell classes. Remove cells with abnormally high counts.

# Remove NeuN samples
Shrew_BC <- subset(Shrew_BC, !( (orig.file == "treeshrew1_neun_pos") |  (orig.file == "treeshrew2_neun_pos") |  (orig.file == "TsNueun") ) )

# Remove cells with high counts
Shrew_BC <- subset(Shrew_BC, subset = nCount_RNA < 25000)

Run clustering pipeline

Run the clustering pipeline again, performing data integration based on the original sample to correct for batch effects.

Shrew_BC <- ClusterSeurat(Shrew_BC, integrate.by = "orig.file", numPCs = 20, cluster_resolution = 0.8)

Visualize initial clusters

DimPlot(Shrew_BC, label = TRUE)

DimPlot(Shrew_BC, group.by = "orig.file", shuffle = TRUE)

VlnPlot(Shrew_BC, "nCount_RNA", pt.size = 0) + RotatedAxis()

VlnPlot(Shrew_BC, "nFeature_RNA", pt.size = 0) + RotatedAxis()

Refine resolution parameter

DefaultAssay(Shrew_BC) <- "integrated"

Shrew_BC <- FindClusters(Shrew_BC, resolution = 0.5)
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 6202
Number of edges: 343929

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.9511
Number of communities: 17
Elapsed time: 0 seconds
Shrew_BC <- FindClusters(Shrew_BC, resolution = 0.8)
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 6202
Number of edges: 343929

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.9223
Number of communities: 17
Elapsed time: 0 seconds
Shrew_BC <- FindClusters(Shrew_BC, resolution = 1.1)
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 6202
Number of edges: 343929

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.8936
Number of communities: 17
Elapsed time: 0 seconds
Shrew_BC <- FindClusters(Shrew_BC, resolution = 1.4)
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 6202
Number of edges: 343929

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.8649
Number of communities: 18
Elapsed time: 0 seconds
DimPlot(Shrew_BC, label = TRUE, group.by = "integrated_snn_res.0.5")

DimPlot(Shrew_BC, label = TRUE, group.by = "integrated_snn_res.0.8")

DimPlot(Shrew_BC, label = TRUE, group.by = "integrated_snn_res.1.1")

DimPlot(Shrew_BC, label = TRUE, group.by = "integrated_snn_res.1.4")

Go with resolution of 1.4, as some clusters might be distinct

Remove contaminant clusters

Examine canonical markers for contaminant clusters.

DotPlot(Shrew_BC, features = BC_markers, assay = "RNA") + RotatedAxis()


DotPlot(Shrew_BC, features = c(RGC_markers, BC_markers, AC_markers, HC_markers, PR_markers, MG_markers, Other_markers), assay = "RNA") + RotatedAxis()


# Cluster 12, 15, 16  express TFAP2, an AC marker
Shrew_BC <- DropClusters(Shrew_BC, idents = c(12,15,16), refactor = FALSE)

# Cluster 5 expresses two HC markers
Shrew_BC <- DropClusters(Shrew_BC, idents = c(5), refactor = TRUE)

Double check AC markers

DotPlot(Shrew_BC, features = AC_markers, assay = "RNA") + RotatedAxis()

Cluster 10 still exhibits AC markers: remove

Merge clusters

Now that contaminants have been removed, reconstruct the neighborhood graph and UMAP.

Calculate top DE genes and plot using a dendrogram.

DefaultAssay(Shrew_BC) <- "RNA"
Shrew_BC <- DendroOrder(Shrew_BC)
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Idents(Shrew_BC) <- "dendro_order"

BC_markers <- FindAllMarkers(Shrew_BC, assay = "RNA", verbose = FALSE, only.pos = TRUE, max.cells.per.ident = 500)

DotPlot(Shrew_BC, features = TopMarkers(BC_markers, num_markers = 2),group.by = "dendro_order") + RotatedAxis()

All clusters seem to be distinct, so no need for further refinement.

Summmary Plots

LS0tCnRpdGxlOiAiQ2xhc3MgYW5kIFR5cGUgQW5ub3RhdGlvbiIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBQcmVwcm9jZXNzaW5nIAoKTG9hZCBuZWNlc3NhcnkgbGlicmFyaWVzIGZvciBhbmFseXNpcwpgYGB7cn0KbGlicmFyeShyZXNoYXBlMikKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoU2V1cmF0RGlzaykKbGlicmFyeShnZ3Bsb3QyKQpzb3VyY2UoInV0aWxzL3V0aWxGeG5zLlIiKQpzb3VyY2UoInV0aWxzL3Bsb3R0aW5nRnhucy5SIikKYGBgCgpHZW5lIGV4cHJlc3Npb24gbWF0cmljZXMgKEdFTSkgZm9yIGVhY2ggc2VxdWVuY2luZyBzYW1wbGUgYXJlIGNvbnZlcnRlZCBmcm9tIGg1YWQgZmlsZXMgdG8gaDVTZXVyYXQgZmlsZXMgYW5kIHRoZW4gcmVhZCBpbi4gRm9yIHRoaXMgZXhhbXBsZSwgd2Ugd2lsbCBiZSByZWFkaW5nIGluIDggZGlmZmVyZW50IHRyZWUgc2hyZXcgc2FtcGxlcy4gCmBgYHtyfQojIFNldCAKZGF0YV9kaXIgPC0gIi9Vc2Vycy9qb3NoaGFobi9Hb29nbGUgRHJpdmUvTXkgRHJpdmUvc2hla2hhcmxhYl9kYXRhL3Byb2plY3RzL1RyZWVfc2hyZXcvVFNfdmVsby8iCiAKCkNvbnZlcnQocGFzdGUwKGRhdGFfZGlyLCAidHJlZXNocmV3MV9jaHgxMF9wb3MvdmVsb19vdXRzL2Z1bGwuaDVhZCIpLCBkZXN0ID0gImg1c2V1cmF0IikKQ2h4MTBfcG9zMSA8LSBMb2FkSDVTZXVyYXQocGFzdGUwKGRhdGFfZGlyLCAidHJlZXNocmV3MV9jaHgxMF9wb3MvdmVsb19vdXRzL2Z1bGwuaDVzZXVyYXQiKSkKCkNvbnZlcnQocGFzdGUwKGRhdGFfZGlyLCAidHJlZXNocmV3MV9uZXVuX2NoeDEwX25lZy92ZWxvX291dHMvZnVsbC5oNWFkIiksIGRlc3QgPSAiaDVzZXVyYXQiKQpOX0NfbmVnMSA8LSBMb2FkSDVTZXVyYXQocGFzdGUwKGRhdGFfZGlyLCAidHJlZXNocmV3MV9uZXVuX2NoeDEwX25lZy92ZWxvX291dHMvZnVsbC5oNXNldXJhdCIpKQoKQ29udmVydChwYXN0ZTAoZGF0YV9kaXIsICJ0cmVlc2hyZXcxX25ldW5fcG9zL3ZlbG9fb3V0cy9mdWxsLmg1YWQiKSwgZGVzdCA9ICJoNXNldXJhdCIpCk5ldW5fcG9zMSA8LSBMb2FkSDVTZXVyYXQocGFzdGUwKGRhdGFfZGlyLCAidHJlZXNocmV3MV9uZXVuX3Bvcy92ZWxvX291dHMvZnVsbC5oNXNldXJhdCIpKQoKQ29udmVydChwYXN0ZTAoZGF0YV9kaXIsICJ0cmVlc2hyZXcyX2NoeDEwX3Bvcy92ZWxvX291dHMvZnVsbC5oNWFkIiksIGRlc3QgPSAiaDVzZXVyYXQiKQpDaHgxMF9wb3MyIDwtIExvYWRINVNldXJhdChwYXN0ZTAoZGF0YV9kaXIsICJ0cmVlc2hyZXcyX2NoeDEwX3Bvcy92ZWxvX291dHMvZnVsbC5oNXNldXJhdCIpKQoKQ29udmVydChwYXN0ZTAoZGF0YV9kaXIsICJ0cmVlc2hyZXcyX25ldW5fY2h4MTBfbmVnL3ZlbG9fb3V0cy9mdWxsLmg1YWQiKSwgZGVzdCA9ICJoNXNldXJhdCIpCk5fQ19uZWcyIDwtIExvYWRINVNldXJhdChwYXN0ZTAoZGF0YV9kaXIsICJ0cmVlc2hyZXcyX25ldW5fY2h4MTBfbmVnL3ZlbG9fb3V0cy9mdWxsLmg1c2V1cmF0IikpCgpDb252ZXJ0KHBhc3RlMChkYXRhX2RpciwgInRyZWVzaHJldzJfbmV1bl9wb3MvdmVsb19vdXRzL2Z1bGwuaDVhZCIpLCBkZXN0ID0gImg1c2V1cmF0IikKTmV1bl9wb3MyIDwtIExvYWRINVNldXJhdChwYXN0ZTAoZGF0YV9kaXIsICJ0cmVlc2hyZXcyX25ldW5fcG9zL3ZlbG9fb3V0cy9mdWxsLmg1c2V1cmF0IikpCgpDb252ZXJ0KHBhc3RlMChkYXRhX2RpciwgIlRzQ2h4MTAvdmVsb19vdXRzL2Z1bGwuaDVhZCIpLCBkZXN0ID0gImg1c2V1cmF0IikKVHNDaHggPC0gTG9hZEg1U2V1cmF0KHBhc3RlMChkYXRhX2RpciwgIlRzQ2h4MTAvdmVsb19vdXRzL2Z1bGwuaDVzZXVyYXQiKSkKCkNvbnZlcnQocGFzdGUwKGRhdGFfZGlyLCAiVHNOdWV1bi92ZWxvX291dHMvZnVsbC5oNWFkIiksIGRlc3QgPSAiaDVzZXVyYXQiKQpUc051IDwtIExvYWRINVNldXJhdChwYXN0ZTAoZGF0YV9kaXIsICJUc051ZXVuL3ZlbG9fb3V0cy9mdWxsLmg1c2V1cmF0IikpCmBgYAoKR0VNcyBmcm9tIGFsbCBzZXF1ZW5jaW5nIHJ1bnMgYXJlIGNvbWJpbmVkIGludG8gYSBzaW5nbGUgU2V1cmF0IG9iamVjdC4gCmBgYHtyfQojIENvbWJpbmUgYWxsIEdFTXMgaW50byBhIHNpbmdsZSBzcGFyc2UgbWF0cml4ClNocmV3X21hdCA8LSBjYmluZChDaHgxMF9wb3MxQGFzc2F5cyRtYXRyaXhAY291bnRzLCBOX0NfbmVnMUBhc3NheXMkbWF0cml4QGNvdW50cywgTmV1bl9wb3MxQGFzc2F5cyRtYXRyaXhAY291bnRzLCBDaHgxMF9wb3MyQGFzc2F5cyRtYXRyaXhAY291bnRzLCBOX0NfbmVnMkBhc3NheXMkbWF0cml4QGNvdW50cywgTmV1bl9wb3MyQGFzc2F5cyRtYXRyaXhAY291bnRzLCBUc0NoeEBhc3NheXMkbWF0cml4QGNvdW50cywgVHNOdUBhc3NheXMkbWF0cml4QGNvdW50cykKCiMgQ3JlYXRlIGEgbmV3IFNldXJhdCBvYmplY3QKU2hyZXcgPC0gQ3JlYXRlU2V1cmF0T2JqZWN0KFNocmV3X21hdCwgbmFtZXMuZGVsaW0gPSAiOiIpCgojIFJldGFpbiBzYW1wbGUgaWRlbnRpdHkgaW4gdGhlIG1ldGFkYXRhLgpTaHJld0BtZXRhLmRhdGFbY29sbmFtZXMoQ2h4MTBfcG9zMSksICdvcmlnLmZpbGUnXSA9ICJ0cmVlc2hyZXcxX2NoeDEwX3BvcyIKU2hyZXdAbWV0YS5kYXRhW2NvbG5hbWVzKE5ldW5fcG9zMSksICdvcmlnLmZpbGUnXSA9ICJ0cmVlc2hyZXcxX25ldW5fcG9zIgpTaHJld0BtZXRhLmRhdGFbY29sbmFtZXMoTl9DX25lZzEpLCAnb3JpZy5maWxlJ10gPSAidHJlZXNocmV3MV9uZXVuX2NoeDEwX25lZyIKU2hyZXdAbWV0YS5kYXRhW2NvbG5hbWVzKENoeDEwX3BvczIpLCAnb3JpZy5maWxlJ10gPSAidHJlZXNocmV3Ml9jaHgxMF9wb3MiClNocmV3QG1ldGEuZGF0YVtjb2xuYW1lcyhOZXVuX3BvczIpLCAnb3JpZy5maWxlJ10gPSAidHJlZXNocmV3Ml9uZXVuX3BvcyIKU2hyZXdAbWV0YS5kYXRhW2NvbG5hbWVzKE5fQ19uZWcyKSwgJ29yaWcuZmlsZSddID0gInRyZWVzaHJldzJfbmV1bl9jaHgxMF9uZWciClNocmV3QG1ldGEuZGF0YVtjb2xuYW1lcyhUc0NoeCksICdvcmlnLmZpbGUnXSA9ICJUc0NoeDEwIgpTaHJld0BtZXRhLmRhdGFbY29sbmFtZXMoVHNOdSksICdvcmlnLmZpbGUnXSA9ICJUc051ZXVuIgpgYGAKClRoZSBpbml0aWFsIFRyZWUgU2hyZXcgb2JqZWN0IGlzIHByb3ZpZGVkLgpgYGB7cn0KU2hyZXcgPC0gcmVhZFJEUygiT2JqZWN0cy9TaHJld19hbGxfY2VsbHNfaW5pdGlhbC5yZHMiKQpgYGAKCkNoZWNrIGVhY2ggc2VxdWVuY2luZyBzYW1wbGVzIGZvciBhbnkgYWJub3JtYWxpdGllcy4KYGBge3IsIHdhcm5pbmc9RkFMU0V9ClZsblBsb3QoU2hyZXcsIGZlYXR1cmVzID0gIm5Db3VudF9STkEiLCBwdC5zaXplID0gMCwgZ3JvdXAuYnkgPSAib3JpZy5maWxlIiwgeS5tYXggPSA1MDAwMCkKVmxuUGxvdChTaHJldywgZmVhdHVyZXMgPSAibkZlYXR1cmVfUk5BIiwgcHQuc2l6ZSA9IDAsIGdyb3VwLmJ5ID0gIm9yaWcuZmlsZSIpCmBgYAoKIyBDZWxsIGNsYXNzIGFubm90YXRpb24KCiMjIENsdXN0ZXIgdGhlIGRhdGEKSGVyZSB3ZSB1c2UgYSBzdGFuZGFyZCBjbHVzdGVyaW5nIHBpcGVsaW5lIHRvIHByb2R1Y2UgYW4gaW5pdGlhbCBzZXQgb2YgY2x1c3RlcnMsIHdoaWNoIHdlIHdpbGwgYW5ub3RhdGUgaW50byB0aGUgbWFqb3IgY2VsbCBjbGFzc2VzLiBUaGUgY2x1c3RlcmluZyBwaXBlbGluZSBoYXMgYmVlbiBjb25kZW5zZWQgaW50byBhIHNpbmdsZSBmdW5jdGlvbiBhdmFpbGFibGUgaW4gdGhlIHV0aWxzIGZvbGRlci4KYGBge3J9ClNocmV3IDwtIENsdXN0ZXJTZXVyYXQoU2hyZXcsIGNsdXN0ZXJfcmVzb2x1dGlvbiA9IDAuNSwgbnVtUENzID0gMjApCmBgYAoKClZpc3VhbGl6ZSBpbml0aWFsIGNsdXN0ZXJzCmBgYHtyfQpEaW1QbG90KFNocmV3LCBsYWJlbCA9IFRSVUUpCkRpbVBsb3QoU2hyZXcsIGdyb3VwLmJ5ID0gIm9yaWcuZmlsZSIpClZsblBsb3QoU2hyZXcsICJuQ291bnRfUk5BIiwgcHQuc2l6ZSA9IDAsIHkubWF4ID0gNTAwMDApICsgUm90YXRlZEF4aXMoKQpWbG5QbG90KFNocmV3LCAibkZlYXR1cmVfUk5BIiwgcHQuc2l6ZSA9IDAsIHkubWF4ID0gNjAwMCkgKyBSb3RhdGVkQXhpcygpCmBgYAoKIyMgSWRlbnRpZnkgY2VsbCBjbGFzc2VzCkdpdmVuIHRoZSBsYXJnZSBudW1iZXIgb2YgY2x1c3RlcnMsIHJlY2x1c3RlciB3aXRoIGEgc21hbGxlciByZXNvbHV0aW9uIHBhcmFtZXRlci4KYGBge3J9ClNocmV3IDwtIEZpbmRDbHVzdGVycyhTaHJldywgcmVzb2x1dGlvbiA9IDAuMikKRGltUGxvdChTaHJldywgbGFiZWwgPSBUUlVFKQpEaW1QbG90KFNocmV3LCBncm91cC5ieSA9ICJvcmlnLmZpbGUiKQpWbG5QbG90KFNocmV3LCAibkNvdW50X1JOQSIsIHB0LnNpemUgPSAwLCB5Lm1heCA9IDUwMDAwKSArIFJvdGF0ZWRBeGlzKCkKVmxuUGxvdChTaHJldywgIm5GZWF0dXJlX1JOQSIsIHB0LnNpemUgPSAwLCB5Lm1heCA9IDYwMDApICsgUm90YXRlZEF4aXMoKQpgYGAKClRvIGFzc2lzdCBpbiBpZGVudGlmeWluZyBjZWxsIGNsYXNzZXMsIGNvbnN0cnVjdCBhIGRlbmRyb2dyYW0gb2YgdGhlIGNsdXN0ZXJzLiBEZW5kcm9PcmRlciBhbHNvIGNyZWF0ZXMgYSBuZXcgbWV0YWRhdGEgY29sdW1uIG9yZGVyZWQgYnkgdGhlIGRlbmRyb2dyYW0uCmBgYHtyfQpTaHJldyA8LSBEZW5kcm9PcmRlcihTaHJldykKYGBgCgpDb25zdHJ1Y3QgYSBEb3RQbG90IG9mIGNhbm9uaWNhbCBtYXJrZXJzLCB3aXRoIGNsdXN0ZXJzIG9yZGVyZWQgYnkgdGhlIGRlbmRyb2dyYW0uCmBgYHtyfQpSR0NfbWFya2Vycz0gYygiUkJQTVMiLCAiUkJQTVMyIiwgIlNMQzE3QTYiLCAiVEhZMSIsICJORUZNIikKQkNfbWFya2Vycz0gYygiVlNYMSIsIk9UWDIiLCAiR1JNNiIsICJUUlBNMSIpCkFDX21hcmtlcnM9IGMoIlRGQVAyQSIsICJURkFQMkIiLCAiVEZBUDJDIiwgIkdBRDEiLCJHQUQyLUFTLTEiLCAgIlNMQzZBOSIsICJDMVFMMSIsICJDMVFMMiIpCkhDX21hcmtlcnM9IGMoIk9ORUNVVDEiLCJPTkVDVVQyIiwgIkxIWDEiLCAiQ0FMQjEiKQpQUl9tYXJrZXJzPSBjKCJQREU2SCIsICJDUlgiLCAiQVJSMyIsICJTQUciKQpNR19tYXJrZXJzPSBjKCJTTEMxQTMiLCJSTEJQMSIsICJBUE9FIikKT3RoZXJfbWFya2Vycz0gYygiUzEwMEIiLCAiR0ZBUCIsICJDMVFBIiwgIkMxUUIiLCAiQ0xETjUiLCAiSUdGQlA3IikKCkRvdFBsb3QoU2hyZXcsIGZlYXR1cmVzID0gYyhSR0NfbWFya2VycywgQkNfbWFya2VycywgQUNfbWFya2VycywgSENfbWFya2VycywgUFJfbWFya2VycywgTUdfbWFya2VycywgT3RoZXJfbWFya2VycyksIGdyb3VwLmJ5ID0gImRlbmRyb19vcmRlciIpICsgUm90YXRlZEF4aXMoKQpgYGAKCkFubm90YXRlIGNsdXN0ZXJzIHVzaW5nIGNhbm9uaWNhbCBtYXJrZXIgZ2VuZXMuCmBgYHtyfQpJZGVudHMoU2hyZXcpIDwtICJzZXVyYXRfY2x1c3RlcnMiCgpTaHJld0BtZXRhLmRhdGEkY2VsbF9jbGFzcyA9ICJVbmFubm90YXRlZCIKU2hyZXdAbWV0YS5kYXRhW1doaWNoQ2VsbHMoU2hyZXcsIGlkZW50cyA9Yyg1NCw0MywyNCwzNiwzNSw2LDE1LDIsMyw0LDMyLDI1LDU3LDE4LDQ0KSksXSRjZWxsX2NsYXNzID0gIlJHQyIKU2hyZXdAbWV0YS5kYXRhW1doaWNoQ2VsbHMoU2hyZXcsIGlkZW50cyA9IGMoMjIsNDYsNTIsMjAsMjcsMzcsNTMsNTAsNTgpKSxdJGNlbGxfY2xhc3MgPSAiQlAiClNocmV3QG1ldGEuZGF0YVtXaGljaENlbGxzKFNocmV3LCBpZGVudHMgPSBjKDI4KSksXSRjZWxsX2NsYXNzID0gIkhDIgpTaHJld0BtZXRhLmRhdGFbV2hpY2hDZWxscyhTaHJldywgaWRlbnRzID0gYyg3LDQyKSksXSRjZWxsX2NsYXNzID0gIk1HIgpTaHJld0BtZXRhLmRhdGFbV2hpY2hDZWxscyhTaHJldywgaWRlbnRzID0gYygyMywgMzQsMjEsNDAsNDUsOSwxOSwxNiw2MiwgNDksMzMsNTEsMTQsNTYsNTksMTMsNDcsNjMsNSwzMSwzMCwxLDgsMTEsNjAsMTAsMTIsNTUsNjEpKSxdJGNlbGxfY2xhc3MgPSAiQUMiClNocmV3QG1ldGEuZGF0YVtXaGljaENlbGxzKFNocmV3LCBpZGVudHMgPSBjKDAsNjUsIDY2LDI2LDY0KSksXSRjZWxsX2NsYXNzID0gIlBSIgoKIyBSZXRhaW4gY2x1c3RlcnMgdGhhdCBkb24ndCBleHByZXNzIGFueSBjYW5vbmljYWwgbWFya2VyIGFzICJPdGhlciIKU2hyZXdAbWV0YS5kYXRhW1doaWNoQ2VsbHMoU2hyZXcsIGlkZW50cyA9IGMoMTcsMjksNDgsNDEsMzgsMzkpKSxdJGNlbGxfY2xhc3MgPSAiT3RoZXIiCmBgYAoKVmlzdWFsaXplIHRoZSBmaW5hbCBhbm5vdGF0aW9ucy4KYGBge3J9CkRpbVBsb3QoU2hyZXcsIGdyb3VwLmJ5ID0gImNlbGxfY2xhc3MiKQpEb3RQbG90KFNocmV3LCBmZWF0dXJlcyA9IGMoUkdDX21hcmtlcnMsIEJDX21hcmtlcnMsIEFDX21hcmtlcnMsIEhDX21hcmtlcnMsIFBSX21hcmtlcnMsIE1HX21hcmtlcnMsIE90aGVyX21hcmtlcnMpLCBncm91cC5ieSA9ICJjZWxsX2NsYXNzIikgKyBSb3RhdGVkQXhpcygpCmBgYAoKU2F2ZSB0aGUgb2JqZWN0LgpgYGB7cn0Kc2F2ZVJEUyhTaHJldywgIk9iamVjdHMvU2hyZXdfYWxsX2NlbGxzX2ZpbmFsLnJkcyIpCmBgYAoKCiMgUkdDIGNsdXN0ZXJpbmcgYW5hbHlzaXMKCk5vdyB0aGF0IHdlIGFubm90YXRlZCB0aGUgbWFqb3IgY2VsbCBjbGFzc2VzLCB3ZSB3aWxsIHNlcGFyYXRlIFJHQ3MgYW5kIEJDcyBpbnRvIHNlcGFyYXRlIG9iamVjdHMgYW5kIGRvIGFub3RoZXIgcm91bmQgb2YgYW5hbHlzaXMuIApgYGB7cn0KIyBSZWFkIGluIHRoZSBmdWxsIG9iamVjdApTaHJldyA8LSByZWFkUkRTKCJPYmplY3RzL1NocmV3X2FsbF9jZWxsc19maW5hbC5yZHMiKQoKIyBTdWJzZXQgdG8gUkdDcwpJZGVudHMoU2hyZXcpIDwtICJjZWxsX2NsYXNzIgpTaHJld19SR0MgPC0gc3Vic2V0KFNocmV3LCBjZWxscyA9IFdoaWNoQ2VsbHMoU2hyZXcsIGlkZW50cyA9IlJHQyIpKQoKIyBFeGFtaW5lIHRoZSBkaXN0cmlidXRpb24gb2YgUkdDcyBhY3Jvc3MgZmlsZXMKVmxuUGxvdChTaHJld19SR0MsICJuQ291bnRfUk5BIiwgZ3JvdXAuYnkgPSAib3JpZy5maWxlIiwgcHQuc2l6ZSA9IC4xKQpWbG5QbG90KFNocmV3X1JHQywgIm5GZWF0dXJlX1JOQSIsIGdyb3VwLmJ5ID0gIm9yaWcuZmlsZSIsIHB0LnNpemUgPSAuMSkKCmBgYAoKV2Ugd2lsbCBvbmx5IGtlZXAgY2VsbHMgZnJvbSBzYW1wbGVzIGVucmljaGVkIGZvciBOZXVOLiBJbiBhZGRpdGlvbiwgcmVtb3ZlIGNlbGxzIHdpdGggYWJub3JtYWxseSBoaWdoIFJOQSBjb3VudHMuCmBgYHtyfQojIE9ubHkga2VlcCBOZXVOIGVucmljaGVkIHNhbXBsZXMKU2hyZXdfUkdDIDwtIHN1YnNldChTaHJld19SR0MsIChvcmlnLmZpbGUgPT0gInRyZWVzaHJldzFfbmV1bl9wb3MiKSB8ICAob3JpZy5maWxlID09ICJ0cmVlc2hyZXcyX25ldW5fcG9zIikgfCAgKG9yaWcuZmlsZSA9PSAiVHNOdWV1biIpKQoKIyBSZW1vdmUgY2VsbHMgd2l0aCBoaWdoIFJOQSBjb3VudHMKU2hyZXdfUkdDIDwtIHN1YnNldChTaHJld19SR0MsIHN1YnNldCA9IG5Db3VudF9STkEgPCAyNTAwMCkKYGBgCgojIyBSdW4gY2x1c3RlcmluZyBwaXBlbGluZQoKUnVuIHRoZSBjbHVzdGVyaW5nIHBpcGVsaW5lIGFnYWluLCBwZXJmb3JtaW5nIGRhdGEgaW50ZWdyYXRpb24gYmFzZWQgb24gdGhlIG9yaWdpbmFsIHNhbXBsZSB0byBjb3JyZWN0IGZvciBiYXRjaCBlZmZlY3RzLiBTdGFydCB3aXRoIGEgY2x1c3RlciByZXNvbHV0aW9uIG9mIDAuOCwgd2hpY2ggd2lsbCBiZSByZWZpbmVkIGxhdGVyLiAKYGBge3J9ClNocmV3X1JHQyA8LSBDbHVzdGVyU2V1cmF0KFNocmV3X1JHQywgIG51bVBDcyA9IDIwLCBpbnRlZ3JhdGUuYnkgPSAib3JpZy5maWxlIiwgY2x1c3Rlcl9yZXNvbHV0aW9uID0gMC44KQpgYGAKClZpc3VhbGl6ZSBpbml0aWFsIGNsdXN0ZXJzLgpgYGB7cn0KRGltUGxvdChTaHJld19SR0MsIGxhYmVsID0gVFJVRSkKRGltUGxvdChTaHJld19SR0MsIGdyb3VwLmJ5ID0gIm9yaWcuZmlsZSIsIHNodWZmbGUgPSBUUlVFKQpWbG5QbG90KFNocmV3X1JHQywgIm5Db3VudF9STkEiLCBwdC5zaXplID0gMCkgKyBSb3RhdGVkQXhpcygpClZsblBsb3QoU2hyZXdfUkdDLCAibkZlYXR1cmVfUk5BIiwgcHQuc2l6ZSA9IDApICsgUm90YXRlZEF4aXMoKQpgYGAKCiMjIFJlZmluZSByZXNvbHV0aW9uIHBhcmFtZXRlcgoKVGVzdCBhIHZhcmlldHkgb2YgcmVzb2x1dGlvbiBwYXJhbWV0ZXJzLgpgYGB7ciwgcmVzdWx0cyA9ICJoaWRlIn0KRGVmYXVsdEFzc2F5KFNocmV3X1JHQykgPC0gImludGVncmF0ZWQiCgpTaHJld19SR0MgPC0gRmluZENsdXN0ZXJzKFNocmV3X1JHQywgcmVzb2x1dGlvbiA9IDAuNSkKU2hyZXdfUkdDIDwtIEZpbmRDbHVzdGVycyhTaHJld19SR0MsIHJlc29sdXRpb24gPSAwLjgpClNocmV3X1JHQyA8LSBGaW5kQ2x1c3RlcnMoU2hyZXdfUkdDLCByZXNvbHV0aW9uID0gMS4xKQpTaHJld19SR0MgPC0gRmluZENsdXN0ZXJzKFNocmV3X1JHQywgcmVzb2x1dGlvbiA9IDEuNCkKCkRpbVBsb3QoU2hyZXdfUkdDLCBsYWJlbCA9IFRSVUUsIGdyb3VwLmJ5ID0gImludGVncmF0ZWRfc25uX3Jlcy4wLjUiKQpEaW1QbG90KFNocmV3X1JHQywgbGFiZWwgPSBUUlVFLCBncm91cC5ieSA9ICJpbnRlZ3JhdGVkX3Nubl9yZXMuMC44IikKRGltUGxvdChTaHJld19SR0MsIGxhYmVsID0gVFJVRSwgZ3JvdXAuYnkgPSAiaW50ZWdyYXRlZF9zbm5fcmVzLjEuMSIpCkRpbVBsb3QoU2hyZXdfUkdDLCBsYWJlbCA9IFRSVUUsIGdyb3VwLmJ5ID0gImludGVncmF0ZWRfc25uX3Jlcy4xLjQiKQpgYGAKClN0YXJ0IHdpdGggdGhlIGNsdXN0ZXJzIGRlY2lkZWQgd2l0aCBhIHJlc29sdXRpb24gb2YgMS40IGFuZCByZWZpbmUgZnJvbSB0aGVyZS4gCmBgYHtyfQpTaHJld19SR0NAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycyA8LSBTaHJld19SR0NAbWV0YS5kYXRhJGludGVncmF0ZWRfc25uX3Jlcy4xLjQKSWRlbnRzKFNocmV3X1JHQykgPC0gInNldXJhdF9jbHVzdGVycyIKYGBgCgojIyBSZW1vdmUgY29udGFtaW5hbnQgY2x1c3RlcnMKCkNoZWNrIGlmIGFueSBjbHVzdGVycyBoYXZlIGFibm9ybWFsbHkgbG93IGNvdW50cyBvciBmZWF0dXJlcy4KCmBgYHtyfQpWbG5QbG90KFNocmV3X1JHQywgIm5Db3VudF9STkEiLCBwdC5zaXplID0gMCkgKyBSb3RhdGVkQXhpcygpClZsblBsb3QoU2hyZXdfUkdDLCAibkZlYXR1cmVfUk5BIiwgcHQuc2l6ZSA9IDApICsgUm90YXRlZEF4aXMoKQpgYGAKCkV4YW1pbmUgY2Fub25pY2FsIG1hcmtlcnMgZm9yIGFueSBwb3RlbnRpYWwgY29udGFtaW5hbnQgY2x1c3RlcnMuIApgYGB7cn0KRG90UGxvdChTaHJld19SR0MsIGZlYXR1cmVzID0gUkdDX21hcmtlcnMsIGFzc2F5ID0gIlJOQSIpICsgUm90YXRlZEF4aXMoKQoKRG90UGxvdChTaHJld19SR0MsIGZlYXR1cmVzID0gYyhSR0NfbWFya2VycywgQkNfbWFya2VycywgQUNfbWFya2VycywgSENfbWFya2VycywgQ29uZV9tYXJrZXJzLCBSb2RfbWFya2VycywgTUdfbWFya2VycywgT3RoZXJfbWFya2VycyksIGFzc2F5ID0gIlJOQSIpICsgUm90YXRlZEF4aXMoKQoKRG90UGxvdChTaHJld19SR0MsIGZlYXR1cmVzID0gQUNfbWFya2VycywgYXNzYXkgPSAiUk5BIikgKyBSb3RhdGVkQXhpcygpCgpgYGAKCgpSZW1vdmUgbG93IHF1YWxpdHkgLyBjb250YW1pbmFudCBjbHVzdGVycy4gIApgYGB7cn0KIyBEcm9wIGNsdXN0ZXIgMCBhbmQgMzIgZHVlIHRvIGxvdyBjb3VudHMKU2hyZXdfUkdDIDwtIERyb3BDbHVzdGVycyhTaHJld19SR0MsIGlkZW50cyA9IGMoMCAsMzIpLCByZWZhY3RvciA9IEZBTFNFKQoKIyBSZW1vdmUgY2x1c3RlcnMgdGhhdCBleHByZXNzIEFDIG1hcmtlcnMsIGFzIHRoZXkgYXJlIGxpa2VseSBBQyBkb3VibGV0cy4KIyBDbHVzdGVyIDMyIGV4cHJlc3NlcyBBQyBtYXJrZXJzLCBidXQgd2FzIGFscmVhZHkgcmVtb3ZlZCBkdWUgdG8gbG93IGNvdW50cy4KU2hyZXdfUkdDIDwtIERyb3BDbHVzdGVycyhTaHJld19SR0MsIGlkZW50cyA9IGMoMTMsIDM5OjQyLCA0NCwgNDUsIDQ4LCA0OSApLCByZWZhY3RvciA9IFRSVUUpCmBgYAoKIyMgTWVyZ2UgY2x1c3RlcnMKCk5vdyB0aGF0IGNvbnRhbWluYW50cyBoYXZlIGJlZW4gcmVtb3ZlZCwgcmVjb25zdHJ1Y3QgdGhlIG5laWdoYm9yaG9vZCBncmFwaCBhbmQgVU1BUC4gCmBgYHtyfQpEZWZhdWx0QXNzYXkoU2hyZXdfUkdDKSA8LSAiaW50ZWdyYXRlZCIKClNocmV3X1JHQyA8LSBGaW5kTmVpZ2hib3JzKFNocmV3X1JHQywgZGltcyA9IDE6MjApClNocmV3X1JHQyA8LSBSdW5VTUFQKFNocmV3X1JHQywgZGltcyA9IDE6MjApCgpEaW1QbG90KFNocmV3X1JHQywgbGFiZWwgPSBUUlVFKQpgYGAKCkNhbGN1bGF0ZSB0b3AgREUgZ2VuZXMgYW5kIHBsb3QgdXNpbmcgYSBkZW5kcm9ncmFtLgpgYGB7cn0KRGVmYXVsdEFzc2F5KFNocmV3X1JHQykgPC0gIlJOQSIKU2hyZXdfUkdDIDwtIERlbmRyb09yZGVyKFNocmV3X1JHQykKCklkZW50cyhTaHJld19SR0MpIDwtICJkZW5kcm9fb3JkZXIiCgpSR0NfbWFya2VycyA8LSBGaW5kQWxsTWFya2VycyhTaHJld19SR0MsIGFzc2F5ID0gIlJOQSIsIHZlcmJvc2UgPSBGQUxTRSwgb25seS5wb3MgPSBUUlVFLCBtYXguY2VsbHMucGVyLmlkZW50ID0gNTAwKQoKRG90UGxvdChTaHJld19SR0MsIGZlYXR1cmVzID0gVG9wTWFya2VycyhSR0NfbWFya2VycywgbnVtX21hcmtlcnMgPSAyKSxncm91cC5ieSA9ICJkZW5kcm9fb3JkZXIiKSArIFJvdGF0ZWRBeGlzKCkKYGBgCgpGcm9tIHRoZSBVTUFQIGFuZCBERSBEb3QgUGxvdCwgZGV0ZXJtaW5lIHdoZXRoZXIgdG8gbWVyZ2UgY2VydGFpbiBjbHVzdGVycy4KYGBge3J9CiMgMTcsIDQwIC0ga2VlcCBhcyBzZXBhcmF0ZSBkdWUgdG8gbXVsdGlwbGUgZGlzdGluZ3Vpc2hpbmcgZ2VuZXMKaWRlbnQuMSA9IDE3CmlkZW50LjIgPSA0MAoKbWFya19kaWYgPC0gRmluZE1hcmtlcnMoU2hyZXdfUkdDLCBpZGVudC4xID0gaWRlbnQuMSwgaWRlbnQuMiA9IGlkZW50LjIpCgojIFBsb3QgdG9wIG1hcmtlcnMgYmFzZWQgb2ZmIG9mIGF2ZXJhZ2UgbG9nLWZvbGQgY2hhbmdlCm1hcmtfZGlmIDwtIG1hcmtfZGlmW29yZGVyKG1hcmtfZGlmJGF2Z19sb2cyRkMpLF0KRG90UGxvdChTaHJld19SR0MsIGlkZW50cyA9IGMoaWRlbnQuMSwgaWRlbnQuMiksIGZlYXR1cmVzID0gYyhoZWFkKHJvd25hbWVzKG1hcmtfZGlmKSksIHRhaWwocm93bmFtZXMobWFya19kaWYpKSkpICsgUm90YXRlZEF4aXMoKQoKIyBQbG90IHRvcCBtYXJrZXJzIGJhc2VkIG9mZiBkaWZmZXJlbmNlIGluIHBlcmNlbnQgZXhwcmVzc2lvbgptYXJrX2RpZiRwY3QuZGlmIDwtIG1hcmtfZGlmJHBjdC4xIC0gbWFya19kaWYkcGN0LjIKbWFya19kaWYgPC0gbWFya19kaWZbb3JkZXIobWFya19kaWYkcGN0LmRpZiksXQpEb3RQbG90KFNocmV3X1JHQywgaWRlbnRzID0gYyhpZGVudC4xLCBpZGVudC4yKSwgZmVhdHVyZXMgPSBjKGhlYWQocm93bmFtZXMobWFya19kaWYpKSwgdGFpbChyb3duYW1lcyhtYXJrX2RpZikpKSkgKyBSb3RhdGVkQXhpcygpCmBgYAoKCmBgYHtyfQojIDIwLCAzNgppZGVudC4xID0gMjAKaWRlbnQuMiA9IDM2CgptYXJrX2RpZiA8LSBGaW5kTWFya2VycyhTaHJld19SR0MsIGlkZW50LjEgPSBpZGVudC4xLCBpZGVudC4yID0gaWRlbnQuMikKCiMgUGxvdCB0b3AgbWFya2VycyBiYXNlZCBvZmYgb2YgYXZlcmFnZSBsb2ctZm9sZCBjaGFuZ2UKbWFya19kaWYgPC0gbWFya19kaWZbb3JkZXIobWFya19kaWYkYXZnX2xvZzJGQyksXQpEb3RQbG90KFNocmV3X1JHQywgaWRlbnRzID0gYyhpZGVudC4xLCBpZGVudC4yKSwgZmVhdHVyZXMgPSBjKGhlYWQocm93bmFtZXMobWFya19kaWYpKSwgdGFpbChyb3duYW1lcyhtYXJrX2RpZikpKSkgKyBSb3RhdGVkQXhpcygpCgojIFBsb3QgdG9wIG1hcmtlcnMgYmFzZWQgb2ZmIGRpZmZlcmVuY2UgaW4gcGVyY2VudCBleHByZXNzaW9uCm1hcmtfZGlmJHBjdC5kaWYgPC0gbWFya19kaWYkcGN0LjEgLSBtYXJrX2RpZiRwY3QuMgptYXJrX2RpZiA8LSBtYXJrX2RpZltvcmRlcihtYXJrX2RpZiRwY3QuZGlmKSxdCkRvdFBsb3QoU2hyZXdfUkdDLCBpZGVudHMgPSBjKGlkZW50LjEsIGlkZW50LjIpLCBmZWF0dXJlcyA9IGMoaGVhZChyb3duYW1lcyhtYXJrX2RpZikpLCB0YWlsKHJvd25hbWVzKG1hcmtfZGlmKSkpKSArIFJvdGF0ZWRBeGlzKCkKCmBgYAoKQXMgbW9zdCBvZiB0aGUgdG9wIG1hcmtlcnMgZm9yIDM2IGFyZSBzdGlsbCBleHByZXNzZWQgaW4gMjAsIGFsdGhvdWdoIGF0IGEgbG93ZXIgZXhwcmVzc2lvbiBsZXZlbCwgbWVyZ2UgdGhlIHR3byBjbHVzdGVycy4KYGBge3J9CiMgMjAsIDM2IC0gbWVyZ2UKU2hyZXdfUkdDIDwtIE1lcmdlQ2x1c3RlcnMoU2hyZXdfUkdDLCBpZGVudHMgPSBjKDIwLDM2KSwgcmVmYWN0b3IgPSBUUlVFKQpgYGAKCiMjIFN1bW1hcnkgUGxvdHMKYGBge3J9ClNocmV3X1JHQ0BtZXRhLmRhdGEkdHlwZSA8LSBTaHJld19SR0NAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycwpJZGVudHMoU2hyZXdfUkdDKSA8LSAidHlwZSIKRGltUGxvdChTaHJld19SR0MsIGxhYmVsID0gVFJVRSkKCnNhdmVSRFMoU2hyZXdfUkdDLCAiT2JqZWN0cy9TaHJld19SR0NfZmluYWwucmRzIikKYGBgCgoKCiMgQkMgY2x1c3RlcmluZyBhbmFseXNpcwoKV2Ugd2lsbCBmb2xsb3cgYSBzaW1pbGFyIHByb2Nlc3MgdG8gbm93IGFuYWx5emUgYmlwb2xhciBjZWxscy4KYGBge3J9ClNocmV3IDwtIHJlYWRSRFMoIk9iamVjdHMvU2hyZXdfYWxsX2NlbGxzX2ZpbmFsLnJkcyIpCgojIE9ubHkga2VlcCBCQ3MKSWRlbnRzKFNocmV3KSA8LSAiY2VsbF9jbGFzcyIKU2hyZXdfQkMgPC0gc3Vic2V0KFNocmV3LCBjZWxscyA9IFdoaWNoQ2VsbHMoU2hyZXcsIGlkZW50cyA9IkJQIikpCgojIEV4YW1pbmUgcXVhbGl0eSBtZXRyaWNzIGJ5IHNhbXBsZQpWbG5QbG90KFNocmV3X0JDLCAibkNvdW50X1JOQSIsIGdyb3VwLmJ5ID0gIm9yaWcuZmlsZSIsIHB0LnNpemUgPSAuMSkKVmxuUGxvdChTaHJld19CQywgIm5GZWF0dXJlX1JOQSIsIGdyb3VwLmJ5ID0gIm9yaWcuZmlsZSIsIHB0LnNpemUgPSAuMSkKCmBgYAoKUmVtb3ZlIE5ldU4gc2FtcGxlcywgYXMgdGhleSBlbnJpY2ggZm9yIGRpZmZlcmVudCBjZWxsIGNsYXNzZXMuIFJlbW92ZSBjZWxscyB3aXRoIGFibm9ybWFsbHkgaGlnaCBjb3VudHMuCmBgYHtyfQojIFJlbW92ZSBOZXVOIHNhbXBsZXMKU2hyZXdfQkMgPC0gc3Vic2V0KFNocmV3X0JDLCAhKCAob3JpZy5maWxlID09ICJ0cmVlc2hyZXcxX25ldW5fcG9zIikgfCAgKG9yaWcuZmlsZSA9PSAidHJlZXNocmV3Ml9uZXVuX3BvcyIpIHwgIChvcmlnLmZpbGUgPT0gIlRzTnVldW4iKSApICkKCiMgUmVtb3ZlIGNlbGxzIHdpdGggaGlnaCBjb3VudHMKU2hyZXdfQkMgPC0gc3Vic2V0KFNocmV3X0JDLCBzdWJzZXQgPSBuQ291bnRfUk5BIDwgMjUwMDApCgpgYGAKCgojIyBSdW4gY2x1c3RlcmluZyBwaXBlbGluZQoKUnVuIHRoZSBjbHVzdGVyaW5nIHBpcGVsaW5lIGFnYWluLCBwZXJmb3JtaW5nIGRhdGEgaW50ZWdyYXRpb24gYmFzZWQgb24gdGhlIG9yaWdpbmFsIHNhbXBsZSB0byBjb3JyZWN0IGZvciBiYXRjaCBlZmZlY3RzLiAKCmBgYHtyfQpTaHJld19CQyA8LSBDbHVzdGVyU2V1cmF0KFNocmV3X0JDLCBpbnRlZ3JhdGUuYnkgPSAib3JpZy5maWxlIiwgbnVtUENzID0gMjAsIGNsdXN0ZXJfcmVzb2x1dGlvbiA9IDAuOCkKYGBgCgpWaXN1YWxpemUgaW5pdGlhbCBjbHVzdGVycwpgYGB7cn0KRGltUGxvdChTaHJld19CQywgbGFiZWwgPSBUUlVFKQpEaW1QbG90KFNocmV3X0JDLCBncm91cC5ieSA9ICJvcmlnLmZpbGUiLCBzaHVmZmxlID0gVFJVRSkKVmxuUGxvdChTaHJld19CQywgIm5Db3VudF9STkEiLCBwdC5zaXplID0gMCkgKyBSb3RhdGVkQXhpcygpClZsblBsb3QoU2hyZXdfQkMsICJuRmVhdHVyZV9STkEiLCBwdC5zaXplID0gMCkgKyBSb3RhdGVkQXhpcygpCmBgYAoKIyMgUmVmaW5lIHJlc29sdXRpb24gcGFyYW1ldGVyCgpgYGB7cn0KRGVmYXVsdEFzc2F5KFNocmV3X0JDKSA8LSAiaW50ZWdyYXRlZCIKClNocmV3X0JDIDwtIEZpbmRDbHVzdGVycyhTaHJld19CQywgcmVzb2x1dGlvbiA9IDAuNSkKU2hyZXdfQkMgPC0gRmluZENsdXN0ZXJzKFNocmV3X0JDLCByZXNvbHV0aW9uID0gMC44KQpTaHJld19CQyA8LSBGaW5kQ2x1c3RlcnMoU2hyZXdfQkMsIHJlc29sdXRpb24gPSAxLjEpClNocmV3X0JDIDwtIEZpbmRDbHVzdGVycyhTaHJld19CQywgcmVzb2x1dGlvbiA9IDEuNCkKCkRpbVBsb3QoU2hyZXdfQkMsIGxhYmVsID0gVFJVRSwgZ3JvdXAuYnkgPSAiaW50ZWdyYXRlZF9zbm5fcmVzLjAuNSIpCkRpbVBsb3QoU2hyZXdfQkMsIGxhYmVsID0gVFJVRSwgZ3JvdXAuYnkgPSAiaW50ZWdyYXRlZF9zbm5fcmVzLjAuOCIpCkRpbVBsb3QoU2hyZXdfQkMsIGxhYmVsID0gVFJVRSwgZ3JvdXAuYnkgPSAiaW50ZWdyYXRlZF9zbm5fcmVzLjEuMSIpCkRpbVBsb3QoU2hyZXdfQkMsIGxhYmVsID0gVFJVRSwgZ3JvdXAuYnkgPSAiaW50ZWdyYXRlZF9zbm5fcmVzLjEuNCIpCmBgYApHbyB3aXRoIHJlc29sdXRpb24gb2YgMS40LCBhcyBzb21lIGNsdXN0ZXJzIG1pZ2h0IGJlIGRpc3RpbmN0CmBgYHtyfQpTaHJld19CQ0BtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzIDwtIFNocmV3X0JDQG1ldGEuZGF0YSRpbnRlZ3JhdGVkX3Nubl9yZXMuMS40CklkZW50cyhTaHJld19CQykgPC0gInNldXJhdF9jbHVzdGVycyIKRGVmYXVsdEFzc2F5KFNocmV3X0JDKSA8LSAiUk5BIgpgYGAKCiMjIFJlbW92ZSBjb250YW1pbmFudCBjbHVzdGVycwoKRXhhbWluZSBjYW5vbmljYWwgbWFya2VycyBmb3IgY29udGFtaW5hbnQgY2x1c3RlcnMuIAoKYGBge3J9CkRvdFBsb3QoU2hyZXdfQkMsIGZlYXR1cmVzID0gQkNfbWFya2VycywgYXNzYXkgPSAiUk5BIikgKyBSb3RhdGVkQXhpcygpCgpEb3RQbG90KFNocmV3X0JDLCBmZWF0dXJlcyA9IGMoUkdDX21hcmtlcnMsIEJDX21hcmtlcnMsIEFDX21hcmtlcnMsIEhDX21hcmtlcnMsIFBSX21hcmtlcnMsIE1HX21hcmtlcnMsIE90aGVyX21hcmtlcnMpLCBhc3NheSA9ICJSTkEiKSArIFJvdGF0ZWRBeGlzKCkKYGBgCgoKYGBge3J9CgojIENsdXN0ZXIgMTIsIDE1LCAxNiAgZXhwcmVzcyBURkFQMiwgYW4gQUMgbWFya2VyClNocmV3X0JDIDwtIERyb3BDbHVzdGVycyhTaHJld19CQywgaWRlbnRzID0gYygxMiwxNSwxNiksIHJlZmFjdG9yID0gRkFMU0UpCgojIENsdXN0ZXIgNSBleHByZXNzZXMgdHdvIEhDIG1hcmtlcnMKU2hyZXdfQkMgPC0gRHJvcENsdXN0ZXJzKFNocmV3X0JDLCBpZGVudHMgPSBjKDUpLCByZWZhY3RvciA9IFRSVUUpCgpgYGAKCkRvdWJsZSBjaGVjayBBQyBtYXJrZXJzCmBgYHtyfQpEb3RQbG90KFNocmV3X0JDLCBmZWF0dXJlcyA9IEFDX21hcmtlcnMsIGFzc2F5ID0gIlJOQSIpICsgUm90YXRlZEF4aXMoKQpgYGAKCkNsdXN0ZXIgMTAgc3RpbGwgZXhoaWJpdHMgQUMgbWFya2VyczogcmVtb3ZlCmBgYHtyfQpTaHJld19CQyA8LSBEcm9wQ2x1c3RlcnMoU2hyZXdfQkMsIGlkZW50cyA9IGMoMTApLCByZWZhY3RvciA9IFRSVUUpCmBgYAoKIyMgTWVyZ2UgY2x1c3RlcnMKCk5vdyB0aGF0IGNvbnRhbWluYW50cyBoYXZlIGJlZW4gcmVtb3ZlZCwgcmVjb25zdHJ1Y3QgdGhlIG5laWdoYm9yaG9vZCBncmFwaCBhbmQgVU1BUC4gCmBgYHtyfQpEZWZhdWx0QXNzYXkoU2hyZXdfQkMpIDwtICJpbnRlZ3JhdGVkIgoKU2hyZXdfQkMgPC0gRmluZE5laWdoYm9ycyhTaHJld19CQywgZGltcyA9IDE6MjApClNocmV3X0JDIDwtIFJ1blVNQVAoU2hyZXdfQkMsIGRpbXMgPSAxOjIwKQoKRGltUGxvdChTaHJld19CQywgbGFiZWwgPSBUUlVFKQpgYGAKCkNhbGN1bGF0ZSB0b3AgREUgZ2VuZXMgYW5kIHBsb3QgdXNpbmcgYSBkZW5kcm9ncmFtLgpgYGB7cn0KRGVmYXVsdEFzc2F5KFNocmV3X0JDKSA8LSAiUk5BIgpTaHJld19CQyA8LSBEZW5kcm9PcmRlcihTaHJld19CQykKCklkZW50cyhTaHJld19CQykgPC0gImRlbmRyb19vcmRlciIKCkJDX21hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnMoU2hyZXdfQkMsIGFzc2F5ID0gIlJOQSIsIHZlcmJvc2UgPSBGQUxTRSwgb25seS5wb3MgPSBUUlVFLCBtYXguY2VsbHMucGVyLmlkZW50ID0gNTAwKQoKRG90UGxvdChTaHJld19CQywgZmVhdHVyZXMgPSBUb3BNYXJrZXJzKEJDX21hcmtlcnMsIG51bV9tYXJrZXJzID0gMiksZ3JvdXAuYnkgPSAiZGVuZHJvX29yZGVyIikgKyBSb3RhdGVkQXhpcygpCmBgYAoKQWxsIGNsdXN0ZXJzIHNlZW0gdG8gYmUgZGlzdGluY3QsIHNvIG5vIG5lZWQgZm9yIGZ1cnRoZXIgcmVmaW5lbWVudC4gCgojIyBTdW1tbWFyeSBQbG90cwpgYGB7cn0KU2hyZXdfQkNAbWV0YS5kYXRhJHR5cGUgPC0gU2hyZXdfQkNAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycwpEZWZhdWx0QXNzYXkoU2hyZXdfQkMpIDwtICJSTkEiCklkZW50cyhTaHJld19CQykgPC0gInR5cGUiCkRpbVBsb3QoU2hyZXdfQkMsIGxhYmVsID0gVFJVRSkKc2F2ZVJEUyhTaHJld19CQywgIk9iamVjdHMvU2hyZXdfQkNfZmluYWwucmRzIikKYGBgCgoK